package edu.lnu.ums.dal.impl;

import java.util.List;

import edu.lnu.ums.dal.IGenericDAO;
import edu.lnu.ums.entities.core.AbstractEntity;
import java.util.Collection;
import javax.persistence.EntityManager;
import javax.persistence.EntityManagerFactory;

public abstract class AbstractGenericDAO<T extends AbstractEntity> implements IGenericDAO<T> {
    protected Class<T> cls;
    
    public AbstractGenericDAO(Class<T> cls) {
        this.cls = cls;
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public List<T> getAllOrdered(EntityManagerFactory factory) {
        EntityManager em = factory.createEntityManager();
        List<T> result = em.createQuery("from " + cls.getSimpleName() + " "
                + getOrderByQuery()).getResultList();
        em.close();
        setEntityManagerFactoryToEntityList(factory, result);
        return result;
    }

    @SuppressWarnings("unchecked")
    @Override
    public List<T> getAllUnordered(EntityManagerFactory factory) {
        EntityManager em = factory.createEntityManager();
        List<T> result = em.createQuery("from " + cls.getSimpleName()).getResultList();
        em.close();
        setEntityManagerFactoryToEntityList(factory, result);
        return result;
    }
    
    @SuppressWarnings("unchecked")
    @Override
    public T getById(EntityManagerFactory factory, Long id) {
        EntityManager em = factory.createEntityManager();
        T t = em.find(cls, id);
        setEntityManagerFactoryToEntity(factory, t);
        em.close();
        return t;
    }

    @Override
    public void persist(EntityManagerFactory factory, T obj) {
        EntityManager em = factory.createEntityManager();
        em.getTransaction().begin();
        em.persist(obj);
        em.flush();
        em.getTransaction().commit();
        em.close();
    }    
    
    @Override
    public abstract void delete(T obj);

    public abstract String getOrderByQuery();

    protected static void setEntityManagerFactoryToEntity(EntityManagerFactory factory,
            AbstractEntity entity) {
        if (entity != null) {
            entity.setFactory(factory);
        }
    }

    protected  static void setEntityManagerFactoryToEntityList(EntityManagerFactory factory,
            Collection<? extends AbstractEntity> collection) {
        for (AbstractEntity entity : collection) {
            setEntityManagerFactoryToEntity(factory, entity);
        }
    }
}
